package org.jsola.hr.service.excel;

import com.alibaba.excel.context.AnalysisContext;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.ObjectUtils;
import org.apache.commons.lang3.StringUtils;
import org.jsola.common.BeanKit;
import org.jsola.exception.ParamException;
import org.jsola.hr.dto.SocBackRecordImportDTO;
import org.jsola.hr.query.EmpSocBackRecordInfoQuery;
import org.jsola.hr.service.IEmpSocBackRecordInfoService;
import org.jsola.hr.service.IEmpSocBackRecordRecordService;
import org.jsola.hr.vo.EmpSocBackRecordInfoListVO;
import org.springframework.stereotype.Component;

import java.math.BigDecimal;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @author lyh
 */
@Slf4j
@Data
@EqualsAndHashCode(callSuper = true)
@Component
public class SocBackRecordImportListener extends BaseAnalysisEventListener<SocBackRecordImportDTO> {

    /**
     * 表头
     */
    private Map<Integer, String> allHeadMap;

    /**
     * List最大盛装数据条数
     */
    private static final Integer MAX_COUNT = 2000;

    /**
     * 校验成功导入信息
     */
    private List<SocBackRecordImportDTO> successList = new ArrayList<>();

    /**
     * 校验失败导入信息
     */
    private List<SocBackRecordImportDTO> failList = new ArrayList<>();

    /**
     * 导入数据
     */
    private List<SocBackRecordImportDTO> dataList = new ArrayList<>();

    /**
     * 校验错误信息的查询条件
     */
    private EmpSocBackRecordInfoQuery query;

    @Override
    public void invoke(SocBackRecordImportDTO data, AnalysisContext context) {
        dataList.add(data);
        if (dataList.size() >= MAX_COUNT) {
            // 入库
            saveData();
            // 存储完成清理 list
            dataList.clear();
        }
    }

    @Override
    public void saveData() {
        IEmpSocBackRecordInfoService empSocBackRecordInfoService =
                BeanKit.getBean(IEmpSocBackRecordInfoService.class);
        List<EmpSocBackRecordInfoListVO> backRecordInfoList =
                empSocBackRecordInfoService.selectBackRecordInfo(query, tokenUser.getSiteId());
        Map<String, EmpSocBackRecordInfoListVO> backRecordMap = backRecordInfoList
                .stream().collect(Collectors.toMap(EmpSocBackRecordInfoListVO::getIdCard, v -> v));
        IEmpSocBackRecordRecordService socBackRecordService =
                BeanKit.getBean(IEmpSocBackRecordRecordService.class);
        // 校验错误
        for (SocBackRecordImportDTO data : dataList) {
            checkError(data, backRecordMap, socBackRecordService);
        }
        socBackRecordService.saveImportRecord(successList, tokenUser);
    }

    @Override
    public void invokeHeadMap(Map<Integer, String> headMap, AnalysisContext context) {
        allHeadMap = headMap;
        List<String> checkHeadList = new ArrayList<>();
        checkHeadList.add("姓名");
        checkHeadList.add("身份证号");
        checkHeadList.add("回款途径");
        checkHeadList.add("回款金额");
        try {
            for (Integer headRow : headMap.keySet()) {
                String importHead = headMap.get(headRow);
                String checkHead = checkHeadList.get(headRow);
                if (!checkHead.equals(importHead)) {
                    throw new ParamException("表头第" + (headRow + 1) + "列应为" + checkHead);
                }
            }
        } catch (IndexOutOfBoundsException e) {
            throw new ParamException("不可增加回款记录模板表头");
        }
    }

    private void checkError(SocBackRecordImportDTO data, Map<String, EmpSocBackRecordInfoListVO> backRecordMap,
                            IEmpSocBackRecordRecordService socBackRecordService) {

        boolean haveError = false;
        StringBuilder errorMsg = new StringBuilder();
        // 错误列和他对应的错误信息
        Map<String, String> errorInfo = new HashMap<>(8);
        if (StringUtils.isEmpty(data.getName())) {
            haveError = true;
            data.setName("--");
            errorInfo.put("name", "姓名不能为空");
            errorMsg.append("姓名不能为空;");
        } else if (StringUtils.isEmpty(data.getIdCard())) {
            haveError = true;
            data.setIdCard("--");
            errorInfo.put("idCard", "身份证号不能为空");
            errorMsg.append("身份证号不能为空;");
        } else if (ObjectUtils.isEmpty(data.getWayStatus())) {
            haveError = true;
            errorInfo.put("wayStatus", "回款途径不能为空");
            errorMsg.append("回款途径不能为空;");
        } else {
            EmpSocBackRecordInfoListVO backRecordInfoList = backRecordMap.get(data.getIdCard());
            if (ObjectUtils.isEmpty(backRecordInfoList)) {
                haveError = true;
                errorInfo.put("name", "未找到回款人");
                errorMsg.append("未找到回款人;");
            } else if (!backRecordInfoList.getName().equals(data.getName())) {
                haveError = true;
                errorInfo.put("name", "未找到回款人");
                errorMsg.append("未找到回款人;");
            } else {
                data.setBackRecordInfo(backRecordInfoList);
            }
            if (StringUtils.isEmpty(data.getAmount())) {
                haveError = true;
                data.setAmount("--");
                errorInfo.put("amount", "回款金额不能为空");
                errorMsg.append("回款金额不能为空;");
            }
            if (checkAmount(data.getAmount())) {
                haveError = true;
                errorInfo.put("amount", "回款金额格式错误");
                errorMsg.append("回款金额格式错误;");
            }
        }
        if (haveError) {
            data.setErrorInfo(errorInfo);
            data.setErrorMsg(errorMsg.toString());
            failList.add(data);
        } else {
            try {
                socBackRecordService.saveImportRecord(Collections.singletonList(data), tokenUser);
            } catch (ParamException paramException) {
                errorInfo.put("amount", paramException.getMessage());
                data.setErrorMsg(paramException.getMessage());
                data.setErrorInfo(errorInfo);
                failList.add(data);
            }
        }
    }

    /**
     * 校验金额格式
     */
    private Boolean checkAmount(String amountStr) {
        try {
            BigDecimal bigDecimal = new BigDecimal(amountStr);
            return bigDecimal.compareTo(BigDecimal.ZERO) < 0;
        } catch (Exception e) {
            return true;
        }
    }
}
